package  
{
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.getTimer;
	
	/**
	 * ...
	 * @author 
	 */
	public class Main extends MovieClip 
	{
		private static const _LENGTH_	:int = 10;
		
		private var matrix:Array;
		private var arrItem:Array;
		
		private var mcItem1:Item;
		private var mcItem2:Item;
		
		public function Main() 
		{
			init();
		}
		
		private function init():void 
		{
			mcItem1 = null;
			mcItem2 = null;
			
			matrix = new Array(_LENGTH_);
			arrItem = new Array(_LENGTH_);
			
			var i:int;
			var j:int;
			
			// create items
			
			var mcItem:Item;
			var color:int;
			var count:int = 8;
			
			for (i = 0; i < _LENGTH_; i++) {
				matrix[i] = new Array(_LENGTH_);				
				arrItem[i] = new Array(_LENGTH_);			
				
				for (j = 0; j < _LENGTH_; j++) {		
					matrix[i][j] = false;
				}
			}
			
			var total:int = 0;
			var random:Point;
			while (total < 5) {					
				random = new Point(Math.floor(Math.random() * _LENGTH_), Math.floor(Math.random() * _LENGTH_));
				if (matrix[random.x][random.y] == false) {
					matrix[random.x][random.y] = true;
					total++;
				}				
			}
			
			for (i = 0; i < _LENGTH_; i++)
			{
				for (j = 0; j < _LENGTH_; j++) 
				{		
					if (matrix[i][j]) {
						color = Math.ceil(Math.random() * 5);
					} else {
						color = -1;
					}
					
					mcItem = new ItemFC();
					mcItem.setData(i, j, matrix[i][j], color);
					mcItem.x = j * mcItem.width;
					mcItem.y = i * mcItem.height;
					mcItem.addEventListener(MouseEvent.CLICK, onClickItem);
					
					arrItem[i][j] = mcItem;
					mcContainer.addChild(mcItem);
				}
			}			
			
			prepare();
		}
		
		private function prepare():void {
			var current:int = currentAvailable();
			var total:int = (current >= 3) ? 3 : current;
			var random:Point;
			var count:int = 0;
			var mcItem:Item;
			var color:int;
			
			//trace(current, total);
			
			while (count < total) {					
				random = new Point(Math.floor(Math.random() * _LENGTH_), Math.floor(Math.random() * _LENGTH_));
				
				if (matrix[random.x][random.y] == false) {
					matrix[random.x][random.y] = true;
					
					mcItem = arrItem[random.x][random.y];
					
					color = Math.ceil(Math.random() * 5);
					mcItem.setData(mcItem.row, mcItem.col, true, color);
					
					Item(arrItem[random.x][random.y]).prepare();
					
					count++;
				}				
			}			
		}
		
		private function moveSmall(target:Item):void {
			
			var random:Point;
			var count:int = 0;
			var mcItem:Item;
			
			while (count < 1) {					
				random = new Point(Math.floor(Math.random() * _LENGTH_), Math.floor(Math.random() * _LENGTH_));
				
				if (matrix[random.x][random.y] == false) {
					matrix[random.x][random.y] = true;
					
					mcItem = Item(arrItem[random.x][random.y]);					
					mcItem.setData(mcItem.row, mcItem.col, true, target.color);					
					mcItem.prepare();
					
					count++;
				}				
			}			
		}
		
		
		
		public function bubble():void {
			
			var i:int;
			var j:int;
			var mcItem:Item;
			
			for (i = 0; i < _LENGTH_; i++) 	{
				for (j = 0; j < _LENGTH_; j++) 	{		
					mcItem = arrItem[i][j];
					
					if (mcItem.small) {
						mcItem.show();
					}
				}
			}		
			
			checkResult();
		}
		
		public function currentAvailable():int {			
			var count:int;
			var i:int;
			var j:int;
			for (i = 0; i < _LENGTH_; i++) 	{
				for (j = 0; j < _LENGTH_; j++) 	{		
					if (matrix[i][j] == false) {
						count ++;
					}
				}
			}
			return count;
		}
		
		private function onClickItem(e:MouseEvent):void 
		{
			var item:Item = e.currentTarget as Item;
			if (mcItem1 == null && item.small) {
				return;
			}
			
			if (mcItem1 == null) {
				if (item.value) {
					mcItem1 = item;
					mcItem1.selected();
				}
			} 
			
			else
			{
				if (mcItem1 != item)
				{
					if (item.value) {
						if (item.small == false) {
					
							mcItem1.unselected();
							
							mcItem1 = item;
							mcItem1.selected();							
							
						} else {
							
							matrix[mcItem1.row][mcItem1.col] = false;
							mcItem1.hide();
							
							moveSmall(item);
							
							item.setData(item.row, item.col, true, mcItem1.color);
							item.show();
							
							mcItem1 = null;
							
							bubble();							
							prepare();
						}
					}
					
					else {
						mcItem2 = item;
						
						findDirection(mcItem1, mcItem2);
					}
				}
			}
			
			
		}
		
		private var queue:Array;
		
		private function findDirection(mcStart:Item, mcEnd:Item):void 
		{
			var start:int = getTimer();
			
			var arrClosed:Array = [];
			
			var path:Array = [new Point(mcStart.row, mcStart.col)];			
			queue = [];
			queue = findAvailblePath(path, mcStart.row, mcStart.col);
			
			var first:Array;
			var x:Point;
			
			var arrNext:Array;
			
			var count:int = 0;
			
			while (queue.length) {
				first = queue.shift();
				
				x = first[first.length - 1];
				
				if (arrClosed.indexOf(x) != -1) {
					continue;
				}
				
				if ((x.x == mcEnd.row) && (x.y == mcEnd.col)) {
					
					matrix[mcItem1.row][mcItem1.col] = false;
					
					mcItem1.hide();
					
					matrix[mcItem2.row][mcItem2.col] = true;
					mcItem2.setData(mcItem2.row, mcItem2.col, true, mcItem1.color);
					mcItem2.show();
					
					mcItem1 = null;
					mcItem2 = null;
					
					bubble();
					prepare();
					
					return;
				}
				
				arrClosed.push(x);
				
				arrNext = findAvailblePath(first, x.x, x.y);
				
				queue = queue.concat(arrNext);
				
			}
			
			mcItem1.unselected();
			mcItem1 = null;
			
			mcItem2.unselected();
			mcItem2 = null;
		}
		
		private function findAvailblePath(path:Array, i:int, j:int):Array 
		{
			var result:Array = [];
			
			var arrPath:Array;
			var point:Point;
			
			if (i - 1 >= 0) {
				if (matrix[i - 1][j] == false) {
					arrPath = [];
					arrPath = path.concat();
					point = new Point(i - 1, j);	
					
					if (indexOf(arrPath, point) == false) {
						arrPath.push(point);
						
						if (checkPathExist(arrPath) == false) {
							result.push(arrPath);
						}
					}
				}
			}
			
			if (i + 1 < _LENGTH_)
			{
				if (matrix[i + 1][j] == false)
				{
					arrPath = [];
					arrPath = path.concat();
					point = new Point(i + 1, j);
					
					if (indexOf(arrPath, point) == false) {
						arrPath.push(point);
						
						if (checkPathExist(arrPath) == false) {
							result.push(arrPath);
						}
					}
				}
			}
			
			if (j - 1 >= 0)
			{
				if (matrix[i][j - 1] == false)
				{
					arrPath = [];
					arrPath = path.concat();
					point = new Point(i, j - 1);
					
					if (indexOf(arrPath, point) == false) {
						arrPath.push(point);
						
						if (checkPathExist(arrPath) == false) {
							result.push(arrPath);
						}
					}
				}
			}
			
			if (j + 1 < _LENGTH_)
			{
				if (matrix[i][j + 1] == false)
				{
					arrPath = [];
					arrPath = path.concat();
					point = new Point(i, j + 1);
					
					if (indexOf(arrPath, point) == false) {
						arrPath.push(point);
						
						if (checkPathExist(arrPath) == false) {
							result.push(arrPath);
						}
					}
				}
			}
			
			return result;
		}
		
		private function checkPathExist(arrPath:Array):Boolean {
			
			var path:Array;
			var end:Point;
			var compare:Point = arrPath[arrPath.length - 1];
			
			for (var i:int = 0; i < queue.length; i ++) {
				path = queue[i];
					
				end = path[path.length - 1];
				
				if (end.x == compare.x && end.y == compare.y) {
					return true;
				}
			}			
			
			return false;
		}
		
		private function checkResult():void 
		{
			traceColor();
			
			var i:int;
			var j:int;
			
			var result:Boolean = true;
			
			for (i = 0; i < _LENGTH_; i++)
			{
				for (j = 0; j < _LENGTH_; j++)
				{
					if (matrix[i][j] == false)
					{
						result = false;
						break;
					}
				}
			}
			
			if (result)
			{
				trace("LOSE");
				return;
			}
			
			checkRow();
			
			checkCol();
			
			checkDiagonUp();
			
			
		}
		
		private function checkLine(arr:Array):void
		{
			if (arr.length < 5)
			{
				return;
			}
			
			var mcItem:Item;
			var arrTemp:Array = [];
			var color:int = -1;
			
			for (var i:int = 0; i < arr.length; i ++) {
				mcItem = arr[i];
				
				if (mcItem.value && (mcItem.small == false) )
				{
					if (color == -1)
					{
						color = mcItem.color;
						arrTemp.push(mcItem);
					}
					else
					{
						if (color != mcItem.color)
						{
							if (arrTemp.length >= 5)
							{
								explose(arrTemp);
								arrTemp = [];
								color = -1;
							}
							else {
								color = mcItem.color;
								arrTemp = [];
								arrTemp.push(mcItem);
							}
						} else {
							arrTemp.push(mcItem);
						}
					}
				} else {
					if (arrTemp.length >= 5)
					{
						explose(arrTemp);
					}
					
					color = -1;
					arrTemp = [];
				}
			}	
		}
		
		private function explose(arr:Array):void
		{
			var mcItem:Item;
			for (var i:int = 0; i < arr.length; i++)
			{
				mcItem = arr[i];
				
				matrix[mcItem.row][mcItem.col] = false;
				mcItem.hide();
			}
		}
		
		private function checkRow():void 
		{
			var arrTemp:Array = [];
			
			for (var i:int = 0; i < _LENGTH_; i++)
			{
				arrTemp = [];				
				for (var j:int = 0; j < _LENGTH_; j++) {
					arrTemp.push(arrItem[i][j]);
				}					
				checkLine(arrTemp);
				
			}
			
		}
		
		private function checkCol():void 
		{
			var arrTemp:Array = [];
			
			for (var j:int = 0; j < _LENGTH_; j++)
			{
				arrTemp = [];				
				for (var i:int = 0; i < _LENGTH_; i++) {
					arrTemp.push(arrItem[i][j]);
				}					
				checkLine(arrTemp);
			}
		}
		
		private function checkDiagonUp():void 
		{
			var arrTemp:Array = [];
			
			for (var i:int = 0; i < _LENGTH_; i++)
			{
				arrTemp = [];
				for (var j:int = 0; j <= i; j++) {
					arrTemp.push(arrItem[j][i - j]);
				}
				checkLine(arrTemp);
			}
		}
		
		private function indexOf(arr:Array, point:Point):Boolean {			
			for (var i:int = 0; i < arr.length; i ++) {
				if (arr[i].x == point.x && arr[i].y == point.y) {
					return true;
				}
			}
			return false;
		}
		
		private function tracePath(arr:Array):void {			
			trace('Path:');
			for (var i = 0; i < arr.length; i++) {
				trace(arr[i]);
			}
			trace('\n');
		}
		
		private function traceColor():void 
		{
			var arr:Array;
			
			for (var i:int = 0; i < _LENGTH_; i++)
			{
				arr = [];
				
				for (var j:int = 0; j < _LENGTH_; j++)
				{
					arr[j] = Item(arrItem[i][j]).color;
				}
				
				trace(arr);
			}
			
			trace("------------------------------------");
		}
		
		//private function test():void 
		//{
			//for (var i:int = 0; i < _LENGTH_; i++)
			//{
				//arrTemp = [];
				//for (var j:int = 0; j <= i; j++) {
					//arrTemp.push(arrItem[i][j - i]);
				//}
				//checkLine(arrTemp);
			//}
		//}
		//
	}
}